package com.gjy.concurrency.clazz;

import lombok.Data;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * @author 宫静雨
 * @version 1.0
 * @since 2023-05-18 10:07:04
 */
public class BlockingQueueTest {

    public static void main(String[] args) throws InterruptedException {

        BlockingQueue<CacheData> queue = new DelayQueue<>();
//        queue.put(new CacheData("hello3", 3000));
//        queue.put(new CacheData("hello5", 5000));
//        queue.put(new CacheData("hello8", 8000));

//        System.out.println(queue.take());
//        System.out.println(queue.take());
//        System.out.println(queue.take());

        System.gc();
    }

    @Data
    private static final class CacheData implements Delayed {

        private final long expire;
        private final String value;

        public CacheData(String value, long expire) {
            this.value = value;
            this.expire = System.currentTimeMillis() + expire;
        }

        @Override
        public long getDelay(@NotNull TimeUnit unit) {
            return unit.convert(expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        @Override
        public int compareTo(@NotNull Delayed o) {
            CacheData data = (CacheData) o;
            return Long.compare(expire, data.getExpire());
        }
    }

    private static void extracted() {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);
        Producer producer = new Producer(queue);
        Consumer consumer1 = new Consumer(queue);
        Consumer consumer2 = new Consumer(queue);

        new Thread(producer).start();
        new Thread(consumer1).start();
        new Thread(consumer2).start();
    }

    private static final class Producer implements Runnable {
        private static final Logger logger = LoggerFactory.getLogger(Producer.class);

        private final BlockingQueue<Integer> queue;

        public Producer(BlockingQueue<Integer> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    queue.put(produce());
                    TimeUnit.SECONDS.sleep(1);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        private Integer produce() {
            int nextInt = ThreadLocalRandom.current().nextInt(20);
            logger.info("nextInt = {}", nextInt);
            return nextInt;
        }

    }

    private static final class Consumer implements Runnable {
        private static final Logger logger = LoggerFactory.getLogger(Consumer.class);

        private final BlockingQueue<Integer> queue;

        public Consumer(BlockingQueue<Integer> queue) {
            this.queue = queue;
        }

        @Override
        public void run() {
            try {
                while (true) {
                    consume(queue.take());
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        private void consume(Integer take) {
            logger.info("take = {}", take);
        }
    }
}
